// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`class_expr.js 1`] = `
/* @flow */
// issue #1191

const Thing = class Thing {
  zark() {
    this.x = 123; // error: property not found (must be declared)
  }
};
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */
// issue #1191

const Thing = class Thing {
  zark() {
    this.x = 123; // error: property not found (must be declared)
  }
};

`;

exports[`contra.js 1`] = `
// Counterexample with contravariant this type

class C {
  next: this; // error (see below for exploit): \`this\` should only appear in
              // covariant positions
}

class D extends C { }

var d = new D();
(d: C).next = new C;
(d.next: D); // sneaky

class A {
  foo<X: this>(that: X) { } // error: can't hide contravariance using a bound
}

class B extends A {
  foo<Y: this>(that: Y) { } // error (see above, catches hidden override)
}

// covariance checks on this type in invariant positions

class Invariant {
  out_object(): { _: this } { return { _: this }; }
  in_object(_: { _: this }) { }
  inout_object: { _: this };

  out_array(): Array<this> { return [this]; }
  in_array(_: Array<this>) { }
  inout_array: Array<this>;
}

// covariance checks on this type as type args

class Misc {
  // Set<X> has invariant X
  out_set(): Set<this> { return new Set().add(this); }
  in_set(_: Set<this>) { }
  inout_set: Set<this>;

  // Promise<X> has covariant X
  async out_promise(): Promise<this> { return this; }
  in_promise(_: Promise<this>) { }
  inout_promise: Promise<this>;

  // Generator<X,Y,Z> has covariant X, covariant Y, contravariant Z
  *out_generator(): Generator<this,this,this> {
    yield this;
    return this;
  }
  in_generator(_: Generator<this,this,this>) { }
  inout_generator: Generator<this,this,this>;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Counterexample with contravariant this type

class C {
  next: this; // error (see below for exploit): \`this\` should only appear in
  // covariant positions
}

class D extends C {}

var d = new D();
(d: C).next = new C();
(d.next: D); // sneaky

class A {
  foo<X: this>(that: X) {} // error: can't hide contravariance using a bound
}

class B extends A {
  foo<Y: this>(that: Y) {} // error (see above, catches hidden override)
}

// covariance checks on this type in invariant positions

class Invariant {
  out_object(): { _: this } {
    return { _: this };
  }
  in_object(_: { _: this }) {}
  inout_object: { _: this };

  out_array(): Array<this> {
    return [this];
  }
  in_array(_: Array<this>) {}
  inout_array: Array<this>;
}

// covariance checks on this type as type args

class Misc {
  // Set<X> has invariant X
  out_set(): Set<this> {
    return new Set().add(this);
  }
  in_set(_: Set<this>) {}
  inout_set: Set<this>;

  // Promise<X> has covariant X
  async out_promise(): Promise<this> {
    return this;
  }
  in_promise(_: Promise<this>) {}
  inout_promise: Promise<this>;

  // Generator<X,Y,Z> has covariant X, covariant Y, contravariant Z
  *out_generator(): Generator<this, this, this> {
    yield this;
    return this;
  }
  in_generator(_: Generator<this, this, this>) {}
  inout_generator: Generator<this, this, this>;
}

`;

exports[`export.js 1`] = `
export class A1 {
  foo(): this { return this; }
  bar(): this { return this; }
}

export class A2<X> {
  foo(): this { return this; }
  bar(): this { return this; }
  qux(x: X): X { return x; }
}

export class A3<X> extends A2<X> {}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
export class A1 {
  foo(): this {
    return this;
  }
  bar(): this {
    return this;
  }
}

export class A2<X> {
  foo(): this {
    return this;
  }
  bar(): this {
    return this;
  }
  qux(x: X): X {
    return x;
  }
}

export class A3<X> extends A2<X> {}

`;

exports[`generics.js 1`] = `
class Generic<X> {
  clone(): Generic<X> { return this; }
}

class Implicit<X> { arg: X; val: X; }
class ImplicitNumber extends Implicit { arg: number; }

(new ImplicitNumber().val: string) // error: number ~> string
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class Generic<X> {
  clone(): Generic<X> {
    return this;
  }
}

class Implicit<X> {
  arg: X;
  val: X;
}
class ImplicitNumber extends Implicit {
  arg: number;
}

(new ImplicitNumber().val: string); // error: number ~> string

`;

exports[`import.js 1`] = `
// Check that imports are handled properly with this types

import { A1 } from './export';
import type { A2 } from './export';
import { A3 } from './export';

class B1 extends A1 {
  foo(): B1 { return new B1(); } // error
}

(new B1().bar(): B1); // OK

class B3<X> extends A3<X> {
  foo(): B3<X> { return new B3(); } // error
}

(new B3().bar(): B3<*>); // OK
(new B3().qux(0): string); // error

(new B3().bar(): A2<*>); // OK
((new B3().bar(): B3<string>): A2<number>); // error
((new B3(): A2<number>).qux(0): string); // error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Check that imports are handled properly with this types

import { A1 } from "./export";
import type { A2 } from "./export";
import { A3 } from "./export";

class B1 extends A1 {
  foo(): B1 {
    return new B1();
  } // error
}

(new B1().bar(): B1); // OK

class B3<X> extends A3<X> {
  foo(): B3<X> {
    return new B3();
  } // error
}

(new B3().bar(): B3<*>); // OK
(new B3().qux(0): string); // error

(new B3().bar(): A2<*>); // OK
((new B3().bar(): B3<string>): A2<number>); // error
((new B3(): A2<number>).qux(0): string); // error

`;

exports[`interface.js 1`] = `
interface I { xs: Array<this>; }
interface J { f(): J; }
class C {
  xs: Array<C>;
  f(): C { return this; }
}
function foo(c: C): I { return c; }
function bar(c: C): J { return c; }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
interface I { xs: Array<this> }
interface J { f(): J }
class C {
  xs: Array<C>;
  f(): C {
    return this;
  }
}
function foo(c: C): I {
  return c;
}
function bar(c: C): J {
  return c;
}

`;

exports[`lib_client.js 1`] = `
(new DoublyLinkedList().prev(): DoublyLinkedList);
(new DoublyLinkedList().next(): DoublyLinkedList)

var MiniImmutable = require("mini-immutable");
class C {
  map: MiniImmutable.OrderedMap<number,string>;
  update() {
    this.map = this.map.set(0,"");
  }
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(new DoublyLinkedList().prev(): DoublyLinkedList);
(new DoublyLinkedList().next(): DoublyLinkedList);

var MiniImmutable = require("mini-immutable");
class C {
  map: MiniImmutable.OrderedMap<number, string>;
  update() {
    this.map = this.map.set(0, "");
  }
}

`;

exports[`self.js 1`] = `
class A {
  foo() { return this; } // return of foo is not annotated to get around
                         // substituting this below
  bar(): this { return new A().foo(); } // same as returning : A, so error
  qux(): this { return this.bar(); } // OK (don't cascade errors)
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class A {
  foo() {
    return this;
  } // return of foo is not annotated to get around
  // substituting this below
  bar(): this {
    return new A().foo();
  } // same as returning : A, so error
  qux(): this {
    return this.bar();
  } // OK (don't cascade errors)
}

`;

exports[`statics.js 1`] = `
// supporting \`this\` type in statics

class A {
  static make(): this { // factory method, whose return type \`this\` (still)
                        // describes instances of A or subclasses of A: the
                        // meaning of the \`this\` type is not changed simply by
                        // switching into a static context
    return new this; // but in a static context, the value \`this\` is bound to
                     // the class, instead of instances of the class
  }
}
class B extends A { } // inherits statics method too, with \`this\` bound to the class

(A.make(): A); // OK
(B.make(): B); // OK
(B.make(): A); // OK
(A.make(): B); // error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// supporting \`this\` type in statics

class A {
  static make(): this {
    // factory method, whose return type \`this\` (still)
    // describes instances of A or subclasses of A: the
    // meaning of the \`this\` type is not changed simply by
    // switching into a static context
    return new this(); // but in a static context, the value \`this\` is bound to
    // the class, instead of instances of the class
  }
}
class B extends A {} // inherits statics method too, with \`this\` bound to the class

(A.make(): A); // OK
(B.make(): B); // OK
(B.make(): A); // OK
(A.make(): B); // error

`;

exports[`test.js 1`] = `
// Examples without \`this\` types (compare with examples below)

class Base {
  foo() { return this; }
  qux() { return new Base; }

  bar() { return this; }
  bar_caller() { return this.bar(); }
}

class Inherit extends Base { }

class Override extends Base {
  foo() { return this; } // OK
  qux() { return this; } // OK, too

  bar() { return new Override; } // OK (cf. error below)
}

class InheritOverride extends Override { }

(new Inherit().foo(): Base);
(new Inherit().foo(): Inherit); // error (cf. OK below)
((new Inherit(): Base).foo(): Base);
(new Override().foo(): Base);
(new Override().foo(): Override); // OK
((new Override(): Base).foo(): Base);

(new InheritOverride().bar_caller(): InheritOverride); // error
                                                       // blame flips below

// Examples with \`this\` types (compare with examples above)

class Base2 {
  foo(): this { return this; }
  qux(): Base2 { return new Base2; }

  bar(): this { return this; }
  bar_caller(): this { return this.bar(); }

  corge(that: this) { }
  grault(that: Base2) { }
}

class Inherit2 extends Base2 { }

class Override2 extends Base2 {
  foo(): this { return this; } // OK
  qux(): this { return this; } // OK, too

  bar(): Override2 { return new Override2; } // error (cf. OK above)
                                             // see exploit below

  corge(that: this) { } // error
                        // see exploit below
  grault(that: this) { } // error, too
}

class InheritOverride2 extends Override2 { }

(new Inherit2().foo(): Base2);
(new Inherit2().foo(): Inherit2); // OK (cf. error above)
((new Inherit2(): Base2).foo(): Base2);
(new Override2().foo(): Base2);
(new Override2().foo(): Override2); // OK
((new Override2(): Base2).foo(): Base2);

(new InheritOverride2().bar_caller(): InheritOverride2); // exploits error above

(new Override2(): Base2).corge(new Base2()); // exploits error above
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Examples without \`this\` types (compare with examples below)

class Base {
  foo() {
    return this;
  }
  qux() {
    return new Base();
  }

  bar() {
    return this;
  }
  bar_caller() {
    return this.bar();
  }
}

class Inherit extends Base {}

class Override extends Base {
  foo() {
    return this;
  } // OK
  qux() {
    return this;
  } // OK, too

  bar() {
    return new Override();
  } // OK (cf. error below)
}

class InheritOverride extends Override {}

(new Inherit().foo(): Base);
(new Inherit().foo(): Inherit); // error (cf. OK below)
((new Inherit(): Base).foo(): Base);
(new Override().foo(): Base);
(new Override().foo(): Override); // OK
((new Override(): Base).foo(): Base);

(new InheritOverride().bar_caller(): InheritOverride); // error
// blame flips below

// Examples with \`this\` types (compare with examples above)

class Base2 {
  foo(): this {
    return this;
  }
  qux(): Base2 {
    return new Base2();
  }

  bar(): this {
    return this;
  }
  bar_caller(): this {
    return this.bar();
  }

  corge(that: this) {}
  grault(that: Base2) {}
}

class Inherit2 extends Base2 {}

class Override2 extends Base2 {
  foo(): this {
    return this;
  } // OK
  qux(): this {
    return this;
  } // OK, too

  bar(): Override2 {
    return new Override2();
  } // error (cf. OK above)
  // see exploit below

  corge(that: this) {} // error
  // see exploit below
  grault(that: this) {} // error, too
}

class InheritOverride2 extends Override2 {}

(new Inherit2().foo(): Base2);
(new Inherit2().foo(): Inherit2); // OK (cf. error above)
((new Inherit2(): Base2).foo(): Base2);
(new Override2().foo(): Base2);
(new Override2().foo(): Override2); // OK
((new Override2(): Base2).foo(): Base2);

(new InheritOverride2().bar_caller(): InheritOverride2); // exploits error above

(new Override2(): Base2).corge(new Base2()); // exploits error above

`;
